package org.anachronos.jeep.agent.attach;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.management.remote.JMXServiceURL;

import org.anachronos.jeep.core.attach.VirtualMachineAttachement;

import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

public class VirtualMachineControl implements VirtualMachineControlMBean {
	private static final Logger logger = Logger.getLogger(VirtualMachineControl.class.getName());
	
	private static final String ME = "___ME____";
	public static final String JMXREMOTE_LOCAL_CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress";

	@Override
	public VirtualMachineAttachement attach(final VirtualMachineAttachement vmAttachment,
			final String configFile) throws Exception {
		final String agentFile = AttachServer.getJarFile();
		assert agentFile.endsWith(".jar");
		assert new File(agentFile).exists();
		logger.info("Agent file:" + agentFile);
		final VirtualMachine vm = attach(vmAttachment);
		final Properties systemProperties = vm.getSystemProperties();
		try {
			
			vm.loadAgent(agentFile, configFile);
			final String connectorAddr = loadJmxAgent(vm, systemProperties);
		    final JMXServiceURL jmxServiceURL = new JMXServiceURL(connectorAddr);
			vmAttachment.setJmxServiceURL(jmxServiceURL);
			return vmAttachment;
		} catch (Exception e) {
			throw new RuntimeException("Agent file:" + agentFile, e);
		}
		finally {
			vm.detach();
		}
	}

	private VirtualMachine attach(final VirtualMachineAttachement vmDescriptor)
			throws AttachNotSupportedException, IOException {
		return VirtualMachine.attach(vmDescriptor.getId());
	}

	public String loadJmxAgent() throws Exception {
		System.setProperty(ME, ME);
		for (final VirtualMachineAttachement vmDesc : list()) {
			final Properties systemProperties = vmDesc.getSystemProperties();
			if (systemProperties.containsKey(ME) && systemProperties.get(ME).equals(ME)) {
				final VirtualMachine vm = attach(vmDesc);
				try {
					return loadJmxAgent(vm, systemProperties);
				} finally {
					vm.detach();
				}
			}
		}
		return "";
	}
	
	private String loadJmxAgent(final VirtualMachine vm, final Properties systemProperties) 
			throws Exception {
		String connectorAddr = getConnectorAddress(vm);
		if (connectorAddr == null) {
		  final String managementAgentFile = 
			  systemProperties.getProperty("java.home") + File.separator 
			  + "lib" + File.separator +
			  "management-agent.jar";
		  vm.loadAgent(managementAgentFile);
		  connectorAddr = getConnectorAddress(vm);
		}
		return connectorAddr;
	}

	
	@Override
	public List<VirtualMachineAttachement> list() {
		final List<VirtualMachineAttachement> result = new ArrayList<VirtualMachineAttachement>();
		for (final com.sun.tools.attach.VirtualMachineDescriptor vmDesc : VirtualMachine.list()) {
			VirtualMachine vm = null;
			try {
				vm = VirtualMachine.attach(vmDesc);
				final VirtualMachineAttachement virtualMachineDescriptor = 
					new VirtualMachineAttachement(vmDesc.id(), vmDesc.displayName(), vm.getSystemProperties());
				result.add(virtualMachineDescriptor);
			} catch(Exception _) {
			} finally {
				if (vm != null) {
					try {
						vm.detach();
					} catch (IOException e) {
					}
				}
			}
			
		}
		return result;
	}
	
	private String getConnectorAddress(final VirtualMachine vm)
			throws IOException {
		final Properties agentProperties = vm.getAgentProperties();
		final String connectorAddr = agentProperties.getProperty(JMXREMOTE_LOCAL_CONNECTOR_ADDRESS);
		return connectorAddr;
	}
}
